#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define BUFFSIZE 256

void validOptions();
void StrCpy(char* filename, char* string, char* target);
void CpuInfo();
void VersionKernel();
void TimeConv (float secs, char* buf);
void UpTime();
void CpuTime();
void MemInfo();
void Disk();
void CtxtChange();
void Procesos();
void Hostname();
void CurDateTime();
void BasicHeader();
void LoadAVG();
void StartTime();
void optS();
void FileSys();
void optL(int interval, int duration);

int main(int argc, char **argv)
{
	int interval, duration;
	char opt;   
	opterr = 0; 
	int flagS = 0;
	int flagL = 0;
        
	while((opt = getopt (argc, argv, "sl:"))!=-1){ 
		switch(opt){
			case 's':
				if(argc==2){
					flagS = 1;
					break;
				}
				else{
					validOptions();
					return 0;
				}
			case 'l':
				if(argc==4){
					flagL = 1;
					break;
				}
				else{
					validOptions();
					return 0;
				}
			default:
				validOptions();
				return 0;						
		}
	}
	
	BasicHeader();
		
	if(flagS) {optS();}
	
	if(flagL){
		sscanf(argv[2], "%u", &interval);
		sscanf(argv[3], "%u", &duration);
		optL(interval,duration);
	}

	return 1;
}

void validOptions(){
	printf("Uso: ksamp [opcion]\n\n");
	printf("Opciones:\n");
	printf("  -s: muestra informacion adicional del sistema\n");
	printf("  -l [interval] [duration]: muestra informacion adicional del sistema y el promedio de carga de 1 minuto, por la duracion [duration] en segundos con un intervalo [interval] en segundos\n");

}

void Hostname(){
	FILE *fd; 
	char nombre[BUFFSIZE];
	fd = fopen("/proc/sys/kernel/hostname","r"); 
	fscanf(fd, "%[^\n]s", nombre);					
	printf("Local Hostname: %s \n", nombre); 
	fclose(fd);
}

void CurDateTime(){
	char fecha[12];
	char hora[13];
	char string[BUFFSIZE];
	StrCpy("/proc/driver/rtc", string, "rtc_date");
	sscanf(string, "rtc_date : %s", fecha);
	StrCpy("/proc/driver/rtc", string, "rtc_time");
	sscanf(string, "rtc_time : %s", hora);
	printf("Date: %s\nTime: %s\n", fecha, hora);
}

void CpuInfo(){
	char string[BUFFSIZE];
	char tipocpu[BUFFSIZE];
	char modelocpu[BUFFSIZE];
	StrCpy("/proc/cpuinfo", string,"vendor_id");
	sscanf(string,"vendor_id : %s",tipocpu);
	StrCpy("/proc/cpuinfo",string,"model name");
	sscanf(string, "model name : %[^\n]c", modelocpu);
	printf ("\nCPU Type: %s \nCPU Model: %s\n", tipocpu, modelocpu);
}

void VersionKernel(){
	FILE *fd; 
	char kernelVersion[BUFFSIZE];
	fd = fopen("/proc/version","r"); 
	fscanf(fd, "%[^(]s", kernelVersion);					
	printf("Kernel version: %s \n", kernelVersion); 
	fclose(fd);
}

void StartTime(){
	char string [BUFFSIZE];
	time_t btime;
	unsigned int aux;
	char inicio[BUFFSIZE];
			
	StrCpy("/proc/stat", string, "btime");
	sscanf(string, "btime %u", &aux);
	btime= (time_t)aux;

	strftime(inicio,sizeof(inicio),"%c", localtime(&btime));
	printf("Start time: %s \n", inicio);
}

void FileSys(){
    FILE *fd;
    char ch;
    int cant_fs;
    fd = fopen("/proc/filesystems","r");
    cant_fs=0;
    while ((ch=fgetc(fd)) != EOF){
         if (ch == '\n'){
                cant_fs=cant_fs+1;
         }
    }
    fclose(fd);
    printf("Cantidad de filesystems soportados: %d \n", cant_fs);
    return;
}

void CpuTime(){
	FILE *fd;
	float user, system, idle;
	char tUser[BUFFSIZE], tSys[BUFFSIZE], tIdle[BUFFSIZE];
	fd = fopen("/proc/stat","r");
	fscanf(fd,"cpu %f %*f %f %f", &user, &system, &idle);
	TimeConv(user/100, tUser);
	printf("UserCPUTime: %s",tUser);
	TimeConv(system/100, tSys);
	printf("SysCPUTime: %s",tSys);
	TimeConv(idle/100, tIdle);	
	printf("IdleCPUTime: %s",tIdle);
	fclose(fd);
}

void Procesos(){
	char string[BUFFSIZE];
	int procesos;
		
	StrCpy("/proc/stat", string, "processes");
	sscanf(string, "processes %u", &procesos);
	
	printf("Processes started: %u\n", procesos);
}

void CtxtChange(){
	char string[BUFFSIZE];
	unsigned int chg;
	
	StrCpy("/proc/stat", string, "ctxt");
	sscanf(string, "ctxt %u", &chg);
	
	printf("Context changes: %u \n", chg);
}

void UpTime(){
	FILE *fd; 
	float time;
	char hms[18];
	fd = fopen("/proc/uptime","r"); 
	fscanf(fd, "%f", &time);
	TimeConv(time, hms);
	printf("System Uptime: %s \n", hms); 
	fclose(fd);
}

void Disk(){
	char string[BUFFSIZE];
	unsigned int read, write, pet;
		
	StrCpy("/proc/diskstats", string, "sda");
	sscanf(string, "sda %u", &read);
	sscanf(string, "sda %*u %*u %*u %*u %u", &write);
	pet = write + read;
	printf("Disk Petitions: %u\n", pet);	
}

void MemInfo(){
	char string[BUFFSIZE];
	unsigned int totalmem, freemem;
		
	StrCpy("/proc/meminfo", string, "MemTotal");
	sscanf(string, "MemTotal: %u", &totalmem);	
	StrCpy("/proc/meminfo", string, "MemFree");
	sscanf(string, "MemFree: %u", &freemem);	
	printf("Free Memory / Total Memory: %u MB / %u MB\n", freemem/1024, totalmem/1024);
}

void LoadAVG(){
	FILE *fd;
	float load;			
	fd = fopen("/proc/loadavg","r");
	fscanf(fd,"%f", &load);			
	printf("Average CPU load on the last minute: %f\n", load);
	fclose(fd);
}

void BasicHeader(){
	printf("\n##############################################\n");
	printf("########Informacion Basica del Sistema########\n");
	printf("##############################################\n\n");
	Hostname();
	CurDateTime();
	CpuInfo();
	VersionKernel();
	FileSys();
	printf("\n");
}

void optS(){
	StartTime();	
	CpuTime();
	Procesos();	
	CtxtChange();
}

void optL(int interval, int duration){
	optS();	
	int i;
	printf("-------------------------------------\n");
	for(i=duration/interval; i>0; i--){		
		Disk();
		MemInfo();
		LoadAVG();
		printf("-------------------------------------\n");
		sleep(interval);
	}
}

void StrCpy(char* filename, char* string, char* target){
	FILE* fd;
	char *leer=NULL;
	char buffer[BUFFSIZE];
	fd=fopen(filename,"r");
	
	while(feof(fd)==0){
		fgets(buffer,BUFFSIZE,fd);
		leer=strstr(buffer,target);
		if(leer!=NULL)
		break;
	}
	fclose (fd);
	strcpy (string,leer);
	return;
}

void TimeConv (float secs, char* buf){
	unsigned int d, h, m;
	float s;
    
    	d = (int) (secs / 86400);
    	secs = secs - (long) (d * 86400);
    	h = (int) (secs / 3600);
    	secs = secs - (long) (h * 3600);
    	m = (int) (secs / 60);
    	secs = secs - (long) (m * 60);
    	s = secs;
    	if (d > 0)
		sprintf (buf, "%3ud %2u:%02u:%02.2f\n", d, h, m, secs);
    	else
		sprintf (buf, "%2u:%02u:%02.2f\n", h, m, s);
}



